﻿#include "protocol/command.h"
#include "protocol/serial.h"
#include "utils/utils.h"
#include <stdlib.h>
#include <string.h>

Command::Command(Enum::ECommand cmd, int pkg_type, bool dync):Encoder() {
    reset();
    this->b_dync = dync;
    u16 key = cmd;
    rsp = key;
    head.version = PROT_VERSION_0;
    head.type = pkg_type;
    head.command = cmd;
    AppendBytes((u8 *)&head, sizeof(head));
}

void Command::reset(){
    status = COMMAND_STATUS_OK;
    head.command = 0xFF;
    serial = nullptr;
    respData = nullptr;
    next = this;
    prev = next;
    retry_thro = 1;
    retry_count = 0;
    b_wait = false;
    b_dync = false;
    b_No_Parser = false;
    timeout = 100;
    time = Utils::timestamp_msec();
}

Command::~Command(){
    //qDebug() << "Destroy command:" << this;
    if (respData != nullptr) {
        delete respData;
        respData = nullptr;
    }
}

Command *Command::with_serial(QObject *sender) {
    this->serial = sender;
    return this;
}

void Command::sendAsync(bool just_wait){
    finish();
    reinterpret_cast<Serial *>(serial)->Send(this, just_wait);
}

bool Command::sendSync(bool just_wait) {
    mutex.lock();
    b_wait = true;
    sendAsync(just_wait);
    waitCond.wait(&mutex);
    mutex.unlock();
    if (respData == nullptr) {
        qDebug() << QDateTime::currentDateTimeUtc() << ":Timeout!!!\n";
        status = COMMAND_STATUS_TIMEOUT;
        return false;
    }
    return onParser();
}

bool Command::onParser() {
    if (respData != nullptr && respData->size() > 0) {
        if (b_No_Parser) {
            return true;
        }
        status = respData->value_u8();
        if(status == 0){
            return true;
        }
    }
    return false;
}

qint64 Command::onPrepare(){
    if (retry_count >= retry_thro) {
        return -1;
    }
    qint64 curr_time = time;
    ++retry_count;
    time = Utils::timestamp_msec() + timeout;
    return curr_time;
}

DataCommand::DataCommand(Enum::ECommand cmd, int addr):
Command(cmd, addr)
{

}
